#include "types.h"
#include "riscv.h"
#include "defs.h"

extern char end[]; // kernel.ld中定义的内核结束符号
//extern char *end;// 不可以使用指针，因为end本身就是一个地址
                   // 而指针的语义是“存储一个地址”

void freerange(void *pa_start, void *pa_end);

#define PHYSTOP 0x80000000L + 128 * 1024 * 1024 //128MB
#define IsFreed 0xdeadbeefdeadbeef  // 用于标记已经被释放的内存


struct mem
{
    struct mem *next;
};

struct {
    struct mem* freelist;
} kmem;

void 
kinit() 
{
    freerange(end, (void*)PHYSTOP); // 从内核结尾分配到物理内存上限（128MB）
}

void 
freerange(void *pa_start, void *pa_end) 
{
    char *p;
    p = (char*)PGROUNDUP((uint64)pa_start); // 对齐到页边界
    for(; p + PGSIZE <= (char*)pa_end; p += PGSIZE) {
        kfree(p);
    }
}

void kfree(void *p) 
{
    struct mem* m;

    m = (struct mem*)p;

    uint64 *magic = (uint64*)p;
    if(*magic == IsFreed) {
        printf("double free\n");
        return;
    }

    *magic = IsFreed; // 标记为已释放
    m->next = kmem.freelist;
    kmem.freelist = m; // 将空闲页插入表头
}

void* 
kalloc(void) 
{
    struct mem* m;
    m = kmem.freelist;
    
    if(m) {
        kmem.freelist = m->next;
    }

    return (void*)m;
}